﻿using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Text.RegularExpressions;

public class GameCore : MonoBehaviour {
	
	public const int MAX_ROWS = 30;
	public const int MAX_COLS = 10;
	
	public const float TOTAL_PLAYER_SPENDTIME = 2.5f;
	public const float TOTAL_PLAYER_S = 4.5f;
	public const float TOTAL_BULLET_SPENDTIME = 1.0f;
	static public Vector3 MAX_DISTANCE;
	
	static public LevelInfo currentLevelInfo;
	static public string currentLevelData;
	static public string levelsData;
	
	static public GameManager gameManager;
	static private UI uiManager;
	
	static public int totalRows;
	
	static public int destroyedRow = -1;
	
	public struct Cell {
		public int row;
		public int col;
		
		public Cell(int iRow, int iCol) {
			row = iRow;
			col = iCol;
		}
	}
	
	// Use this for initialization
	void Start () {
		
	}
	
	// Update is called once per frame
	void Update () {
	
	}
	
	static public void InitData () {
		
		GameObject gameManagerObject = GameObject.Find("GameManager");
		gameManager = gameManagerObject.GetComponent<GameManager>();
		
		GameObject uiManagerObject = GameObject.Find("UI");
		uiManager = uiManagerObject.GetComponent<UI>();
		
		TextAsset tmpData = Resources.Load("Levels") as TextAsset;
		levelsData = tmpData.text;
		
		MAX_DISTANCE = new Vector3(0,4,0);
	}
	
	static public void InitLevel (int levelIndex) {

		//Load level's data from string, then split all rows for browse
		string levelName = "level" + levelIndex.ToString();
		currentLevelData = GameIO.ReadDataFromString(levelsData, "levels", levelName);
		string[] arrRows = currentLevelData.Split('|');
		
		totalRows = int.Parse(arrRows[0]); //Total rows of this level
		int totalCols = int.Parse(arrRows[1]); //Total column of this level
		
		//Innitial 2D array using to save grid's data
		GameManager.currentLevelGrid = new byte[totalRows,totalCols];
		GameManager.currentLevelObjects = new GameObject[totalRows,totalCols];
		int row = 0;
		int col = 0;
		
		//Browse for all rows
		for(int i=arrRows.Length-1; i>1; i--) {
			
			//Browse for all columns of this row
			string[] arrCols = arrRows[i].Split(' ');
			for(col=0; col<arrCols.Length; col++) {
				
				//Cell value - enemy's ship color
				byte cellValue = byte.Parse(arrCols[col]);
				GameManager.currentLevelGrid[row,col] = cellValue;
				
				//Cell object - enemy's ship
				string cellName = row.ToString() + "x" + col.ToString();
				GameObject cell = GameObject.Find(cellName);
				GameManager.currentLevelObjects[row,col] = cell;
				
				if(cellValue > 0) { //Set texture for cells

					//Set texture package for sprite animation of spaceship
					Spriter spriter = cell.AddComponent<Spriter>();
					if(cellValue == 1) {
						spriter.texturesPack = gameManager.enemyTexturePack1;
					}
					else if(cellValue == 2) {
						spriter.texturesPack = gameManager.enemyTexturePack2;
					}
					else if(cellValue == 3) {
						spriter.texturesPack = gameManager.enemyTexturePack3;
					}
					
					//Set color
					Enemy enemy = cell.AddComponent<Enemy>();
					enemy.color = cellValue;
				}
				else { //Destroy empty cells
					Destroy(cell);
				}
			}
			
			row++;
		}
		
		//Destroy all remain empty cells
		for(int j=arrRows.Length-2; j<MAX_ROWS; j++) {
			for(col=0; col<MAX_COLS; col++) {
				string cellName = j.ToString() + "x" + col.ToString();
				GameObject cell = GameObject.Find(cellName);
				Destroy(cell);
			}
		}
	}
	
	//Get cell's row and col from object name
	static public Cell GetCellFromObjectName (string objectName) {
		string[] arrName = objectName.Split('x');
		int row = int.Parse(arrName[0]);
		int col = int.Parse(arrName[1]);
		
		Cell cell = new Cell(row,col);
		
		return cell;
	}
	
	public IEnumerator Shoot (List<GameObject> line, GameObject player) {
		
		foreach(GameObject cell in line) {
			Debug.Log(cell.name);
		}
		
		//Get enemy position
		GameObject lastEnemy = line[line.Count-1];
		Vector3 targetEnemyPosition = lastEnemy.transform.position;
		
		//Get target position to move player's ship to
		Vector3 playerTargetPosition = targetEnemyPosition;
		playerTargetPosition.y = player.transform.position.y;
		playerTargetPosition.z = player.transform.position.z;
		
		//Calculate for player's spendtime
		float s = Mathf.Abs(playerTargetPosition.x) + Mathf.Abs(player.transform.position.x);
		float spendTime = (s*TOTAL_PLAYER_SPENDTIME)/TOTAL_PLAYER_S;
		
		//Move player's ship
		if(playerTargetPosition != player.transform.position) {
			EKTween.MoveTo(player, EKTween.EKDict("position", playerTargetPosition, "time", spendTime, "easetype", EKTween.EaseType.EaseOutQuard));
			yield return new WaitForSeconds(spendTime);
		}
		
		//Instantiate the bullet
		GameObject bullet = GameManager.currentBullet;
		bullet.transform.parent = null;
		//GameObject bullet = Instantiate(gameManager.bulletPrefab) as GameObject;
		//bullet.transform.position = playerTargetPosition;

		//Get target position to move the bullet to
		Vector3 bulletTargetPosition = MAX_DISTANCE;
		bulletTargetPosition.x = targetEnemyPosition.x;
		bulletTargetPosition.z = targetEnemyPosition.z + 0.04f;
		
		//Set target enemies for the bullet
		Bullet bulletScript = bullet.GetComponent<Bullet>();
		bulletScript.targetLine = line;
		bulletScript.color = GameManager.currentBulletColor;
		
		//Move the bullet
		EKTween.MoveTo(bullet, EKTween.EKDict("position", bulletTargetPosition, "time", TOTAL_BULLET_SPENDTIME, "easetype", EKTween.EaseType.Linear));

	}
	
	//Super boom
	public void SuperBoom (GameObject targetEnemy) {
		
		Cell cell = GetCellFromObjectName(targetEnemy.name);
		
		List<GameObject> enemies = new List<GameObject>();
		
		if(IsCellExist(cell.row+1,cell.col+1)) {
			enemies.Add(GameManager.currentLevelObjects[cell.row+1,cell.col+1]);
		}
		
		if(IsCellExist(cell.row-1,cell.col-1)) {
			enemies.Add(GameManager.currentLevelObjects[cell.row-1,cell.col-1]);
		}
		
		if(IsCellExist(cell.row+1, cell.col-1)) {
			enemies.Add(GameManager.currentLevelObjects[cell.row+1,cell.col-1]);	
		}
		
		if(IsCellExist(cell.row-1, cell.col+1)) {
			enemies.Add(GameManager.currentLevelObjects[cell.row-1,cell.col+1]);
		}
		
		if(IsCellExist(cell.row+1, cell.col)) {
			enemies.Add(GameManager.currentLevelObjects[cell.row+1,cell.col]);
		}
		
		if(IsCellExist(cell.row-1, cell.col)) {
			enemies.Add(GameManager.currentLevelObjects[cell.row-1,cell.col]);
		}
		
		if(IsCellExist(cell.row, cell.col+1)) {
			enemies.Add(GameManager.currentLevelObjects[cell.row,cell.col+1]);
		}
		
		if(IsCellExist(cell.row, cell.col-1)) {
			enemies.Add(GameManager.currentLevelObjects[cell.row,cell.col-1]);
		}
		
		if(IsCellExist(cell.row, cell.col)) {
			enemies.Add(GameManager.currentLevelObjects[cell.row,cell.col]);
		}
		
		StartCoroutine(DestroyLine(enemies,null));
		
	}
	
	static public bool IsCellExist (int row, int col) {
		
		bool isExist = false;
		if(row >=0 && row < totalRows && col >=0 && col <= 9) {
			GameObject cell = GameManager.currentLevelObjects[row,col];
			if(cell != null) {
				isExist = true;
			}
		}
		
		return isExist;
	}
	
	//Destroy list of enemy's spaceship
	public IEnumerator DestroyLine (List<GameObject> line, List<GameObject> selectionLine) {
		
		//Browse for all enemy's spaceship
		for(int i=line.Count-1; i>=0; i--) {
			
			//Get cell
			GameObject cell = line[i];
			
			//Destroy selection line
			if(selectionLine != null) {
				Destroy(selectionLine[i]);
			}
			
			//Destroy cell (enemy's spaceship)
			if(i<=2) {
				GameCore.DestroyCell(cell, GameCore.gameManager.explosionNormal);
			}
			else if(i<=4) {
				GameCore.DestroyCell(cell, GameCore.gameManager.explosionSmallCombo);
			}
			else {
				GameCore.DestroyCell(cell, GameCore.gameManager.explosionBigCombo);
			}
			
			//Increase score effect
			
			
			//Plus score
			GameManager.playerScore = GameManager.playerScore + (50 + i*10);
			
			yield return new WaitForSeconds(0.15f);
		}
	}
	
	//Destroy cell - enemy's spaceship
	static public void DestroyCell (GameObject cellObject, GameObject explosionPrefab) {
		
		//Instantiate explostion prefab into cell's position
		GameObject explostion = Instantiate(explosionPrefab) as GameObject;
		
		if(cellObject != null) {
			explostion.transform.position = cellObject.transform.position;
		
			//Reset value of cell in grid and destroy cell object
			Cell cell = GetCellFromObjectName(cellObject.name);
			GameManager.currentLevelGrid[cell.row,cell.col] = 0;
			GameManager.currentLevelObjects[cell.row,cell.col] = null;
			Destroy(cellObject);

			CheckRemainRow();
		}
	}
	
	//Check object1 and object2 is nearest cells
	static public bool isNearestCell (string objectName1, string objectName2) {
		
		bool isNearest = false;
		
		Cell cell1 = GetCellFromObjectName(objectName1);
		Cell cell2 = GetCellFromObjectName(objectName2);
		
		if(((cell1.col == cell2.col-1 || cell1.col == cell2.col+1 || cell2.col == cell1.col-1 || cell2.col == cell1.col+1) && cell1.row == cell2.row) ||
			((cell1.row == cell2.row-1 || cell1.row == cell2.row+1 ||cell2.row == cell1.row-1 || cell2.row == cell1.row+1) && cell1.col == cell2.col))
		{
			isNearest = true;
		}
		
		return isNearest;
	}
	
	static public void CheckRemainRow () {
		
		if(CheckWin() == true) {
			GameManager.isWin = true;
			return;
		}
		
		int focusRow = destroyedRow+1;
		for(int i=0; i<=9; i++) {
			if(IsCellExist(focusRow, i) == true) {
				return;
			}
		}
		
		Vector3 newPosition = gameManager.gridBase.transform.position;
		newPosition.y = newPosition.y - 0.48f;
		EKTween.MoveTo(gameManager.gridBase, EKTween.EKDict("position", newPosition, "time", 0.2f, "easetype", EKTween.EaseType.Linear));
		destroyedRow++;
	}
	
	static public bool CheckWin () {
		
		foreach(GameObject enemy in GameManager.currentLevelObjects) {
			if(enemy != null) {
				Debug.Log(enemy.name);
				return false;
			}
		}
		
		return true;
	}
}
